//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Text.RegularExpressions;
using System.Web;
using System.Xml;

using CommunityServer.Blogs.Components;
using CommunityServer.Components;

namespace CommunityServer.Blogs.Components
{
    /// <summary>
    /// Summary description for TrackBackHandler.
    /// </summary>
    public class TrackBackHandler : IHttpHandler
    {
        public TrackBackHandler()
        {
        }

        public void ProcessRequest(HttpContext context)
        {

            context.Response.ContentType = "text/xml";
            CSContext cntx = CSContext.Current;


            User user = cntx.User;
            int postId = 0;
            try
            {
                postId = int.Parse(context.Request.QueryString["postid"]);
            }
            catch
            {
                trackbackResponse(context, 1, "EntryID is invalid or missing");
            }


            if (context.Request.HttpMethod == "POST")
            {
                string title = safeParam(context, "title");
                string excerpt = safeParam(context, "excerpt");
                string url = safeParam(context, "url");
                string blog_name = safeParam(context, "blog_name");

                if (!Globals.IsNullorEmpty(excerpt))
                    excerpt = Formatter.RemoveHtml(excerpt, 250);

                try
                {
                    // is the url valid ?
                    if (url == "")
                    {
                        trackbackResponse(context, 1, "no url parameter found, please try harder!");
                    }

                    string pageTitle = null;

                    WeblogPost trackedEntry = WeblogPosts.GetPost(postId, false, true, false);


                    if (trackedEntry == null)
                    {
                        trackbackResponse(context, 2, "The link does not exist");
                        return;
                    }

                    Weblog wl = trackedEntry.Section as Weblog;

                    Permissions.AccessCheck(wl, Permission.View, user);

                    if (!wl.ValidateTrackBacks(trackedEntry))
                    {
                        trackbackResponse(context, 2, "Trackbacks are not enabled");
                        return;
                    }

                    if (!IsNewTrackBack(trackedEntry, url))
                    {
                        trackbackResponse(context, 2, "Trackbacks already exists");
                        return;

                    }

                    if (!SourceContainsTarget(url, Globals.FullPath(BlogUrls.Instance().Post(trackedEntry, wl)), out pageTitle))
                    {
                        trackbackResponse(context, 2, "Sorry couldn't find a relevant link in " + url);
                    }


                    WeblogPost entry = new WeblogPost();
                    entry.BlogPostType = BlogPostType.Trackback;
                    entry.SectionID = wl.SectionID;
                    entry.ParentID = postId;
                    entry.Subject = title;
                    entry.TitleUrl = url;
                    entry.TrackBackName = blog_name;
                    entry.Body = excerpt;
                    entry.IsApproved = true;
                    entry.PostDate = DateTime.Now;
                    entry.UserTime = DateTime.Now;

                    int trackbackPostID;
                    BlogPostResults status = WeblogPosts.Add(entry, user, out trackbackPostID);

                    if (status != BlogPostResults.Success)
                        trackbackResponse(context, 2, "Failed to save Trackback.");

                    // Log success message to EventLog
                    string message = String.Format("Trackback request received by Community Server for PostID {0} and successfully saved as PostID {1}.", postId, trackbackPostID);
                    EventLogs.Info(message, "Weblogs", 300, cntx.SettingsID);

                }
                catch (System.Threading.ThreadAbortException) { }
                catch (System.Exception ex)
                {
                    if (ex.Message != null)
                        trackbackResponse(context, 0, string.Format("Error occurred while processing Trackback: {0}", ex.Message));
                    else
                        trackbackResponse(context, 0, "Unknown error occurred while processing Trackback.");
                }

            }
            else
            {

                WeblogPost entry = WeblogPosts.GetPost(postId, false, true, false);
                Weblog wl = entry.Section as Weblog;

                Permissions.AccessCheck(wl, Permission.View, user);

                XmlTextWriter w = new XmlTextWriter(context.Response.Output);
                w.Formatting = Formatting.Indented;

                w.WriteStartDocument();
                w.WriteStartElement("response");
                w.WriteElementString("error", "0");
                w.WriteStartElement("rss");
                w.WriteAttributeString("version", "0.91");
                w.WriteStartElement("channel");
                w.WriteElementString("title", entry.Subject);
                w.WriteElementString("link", BlogUrls.Instance().TrackbackPingUrl(wl.ApplicationKey, postId));
                w.WriteElementString("description", "");
                w.WriteElementString("language", "en-us");

                w.WriteEndElement(); // channel
                w.WriteEndElement(); // rss 
                w.WriteEndElement(); // response
                w.WriteEndDocument();

            }

        }

        public bool IsReusable
        {
            get { return false; }
        }

        private void trackbackResponse(HttpContext context, int errNum, string errText)
        {
            // Log trackback failure messae to the EventLog
            string message = String.Format("Trackback request received by Community Server but failed due to one or more reasons. The request URL was [{0}]. Error message returned was: {1}.", context.Request.RawUrl, errText);
            EventLogs.Warn(message, "Weblogs", 300, CSContext.Current.SettingsID);

            XmlDocument d = new XmlDocument();
            XmlElement root = d.CreateElement("response");
            d.AppendChild(root);
            XmlElement er = d.CreateElement("error");
            root.AppendChild(er);
            er.AppendChild(d.CreateTextNode(errNum.ToString()));
            if (errText != "")
            {
                XmlElement msg = d.CreateElement("message");
                root.AppendChild(msg);
                msg.AppendChild(d.CreateTextNode(errText));
            }
            d.Save(context.Response.Output);
            context.Response.End();
        }

        private string safeParam(HttpContext context, string pName)
        {
            if (context.Request.Form[pName] != null)
                return context.Request.Form[pName];
            return string.Empty;
        }

        public static bool SourceContainsTarget(string sURI, string tURI, out string pageTitle)
        {
            pageTitle = string.Empty;
            string page = CSRequest.GetPageText(sURI, tURI);

            // Look for a matching path & query only. Skip the host/port part of the URI because
            //	the body may be using relative URLS for intra-site links.
            Uri target = new Uri(tURI);
            if (page == null || page.IndexOf(target.PathAndQuery) < 0)
                return false;

            string pat = @"<head.*?>.*<title.*?>(.*)</title.*?>.*</head.*?>";
            Regex reg = new Regex(pat, RegexOptions.IgnoreCase | RegexOptions.Singleline);
            Match m = reg.Match(page);
            if (m.Success)
            {
                pageTitle = m.Result("$1");
                return true;
            }

            return false;
        }

        private static bool IsNewTrackBack(WeblogPost post, string trackbackUrl)
        {
            BlogThreadQuery query = new BlogThreadQuery();
            query.SectionID = post.SectionID;
            query.IncludeCategories = false;
            query.PostID = post.PostID;
            query.ReturnFullThread = true;

            PostSet ps = WeblogPosts.GetPosts(query, false);
            ps.Organize();

            foreach (WeblogPost p in ps.Replies)
            {
                if ((string.Compare(trackbackUrl, p.TitleUrl, true) == 0) && (p.BlogPostType == BlogPostType.Trackback))
                    return false;
            }

            return true;
        }
    }
}

